
#include <cstdio>
#include <BRender>
#include <BPainter>
#include <BScene>
#include <BShape>
#include <BViewer>
#include <BMouseEvent>

#include "MainHandler.h"

MainHandler::MainHandler()
{
	_shapeBoxVisible = true;
	_frustumVisible = true;
	_frustumSpaceVisible = true;

	_enableLights = new BLightArray();
	_visualNodes = new BNodeArray();
	_constSceneItems = new ConstSceneTreeItemArray();

	connect("line-changed", &MainHandler::slotLineChanged);
}
MainHandler::~MainHandler()
{

}

void MainHandler::setTargetCamera(BCamera* camera)
{
	if (_targetCamera != camera)
	{
		if (_targetCamera)
			disconnect(_targetCamera);
		_targetCamera = camera;
		if (_targetCamera)
			connect(_targetCamera, Signal_Freshed, &MainHandler::slotTargetCameraFreshed);
	}
}
void MainHandler::setTargetScene(BScene* scene)
{
	if (_targetScene != scene)
	{
		if (_targetScene)
			disconnect(_targetScene);
		_targetScene = scene;
		if (_targetScene)
			connect(_targetScene, Signal_Optimized, &MainHandler::slotTargetSceneOptimizedChanged);
	}
}
void MainHandler::setShapeBoxVisible(bool shapeBoxVisible)
{
	_shapeBoxVisible = shapeBoxVisible;
	this->fresh();
}
void MainHandler::setFrustumVisible(bool frustumVisible)
{
	_frustumVisible = frustumVisible;
	this->fresh();
}
void MainHandler::setFrustumSpaceVisible(bool frustumSpaceVisible)
{
	_frustumSpaceVisible = frustumSpaceVisible;
	this->fresh();
}

void MainHandler::slotTargetCameraFreshed()
{
	this->fresh();
}
void MainHandler::slotTargetSceneOptimizedChanged()
{
	ConstSceneTreeItemArray& constSceneItems = _constSceneItems;
	if (constSceneItems.size())
	{
		constSceneItems.clear();
		this->fresh();
	}
}
void MainHandler::slotLineChanged(BObject* object, const BValue& value)
{
	_line = value;
	this->fresh();
}

void MainHandler::paint(BPainter& painter)
{

}
void MainHandler::render(BRender& render)
{
	_frustum = _targetCamera->query("frustum");
	_targetCamera->query("lights", _enableLights);

	render.setLighting(false);
	render.setDepthTest(true);

	render.setColor(0, 255, 0);
	render.setLineWidth(3);
	render.drawLine(_line);

	if (_targetCamera)
	{
		BVector pos = _targetCamera->position();
		BVector center = _targetCamera->center();

		render.setColor(255, 255, 255);
		render.setLineWidth(3);
		render.drawLine(pos, center);
	}

	_frustum = _targetCamera->query("frustum");
	if (_frustumVisible)
	{
		const BVector& near_v0 = _frustum.near(0);
		const BVector& near_v1 = _frustum.near(1);
		const BVector& near_v2 = _frustum.near(2);
		const BVector& near_v3 = _frustum.near(3);

		const BVector& far_v0 = _frustum.far(0);
		const BVector& far_v1 = _frustum.far(1);
		const BVector& far_v2 = _frustum.far(2);
		const BVector& far_v3 = _frustum.far(3);

		render.setColor(255, 0, 0, 200);
		render.fillQuad(near_v0, near_v1, near_v2, near_v3);
		render.fillQuad(far_v0, far_v1, far_v2, far_v3);
		render.setColor(255, 255, 0, 200);
		render.fillQuad(near_v0, near_v1, far_v1, far_v0);
		render.fillQuad(near_v2, near_v3, far_v3, far_v2);
	}

	if (_frustumSpaceVisible)
	{
		BSpace frustumSpace = _frustum.space();
		render.setColor(255, 255, 255);
		render.drawSpace(frustumSpace);
	}

	static BValue pairsValue;
	if (_shapeBoxVisible && _targetCamera->query("visual-pairs", pairsValue))
	{
		const BArray<BNodeShapePair>& visualPairs = pairsValue;
		render.setLineWidth(1);
		render.setCullback(false);
		render.setColor(255, 255, 255);
		for (int i = 0; i < visualPairs.size(); i++)
		{
			const auto& pair = visualPairs[i];
			BShape* shape = pair.value();
			BBox box = shape->box() * shape->matrix();
			if (BNode* node = pair.key())
				box *= node->matrix();
			render.drawBox(box);
		}
	}

	static BValue transparentPairsValue;
	if (_shapeBoxVisible && _targetCamera->query("visual-transparent-pairs", transparentPairsValue))
	{
		const BArray<BNodeShapePair>& transparentPairs = transparentPairsValue;
		render.setColor(0, 255, 255);
		for (int i = 0; i < transparentPairs.size(); i++)
		{
			const auto& pair = transparentPairs[i];
			BShape* shape = pair.value();
			BBox box = shape->box() * shape->matrix();
			if (BNode* node = pair.key())
				box *= node->matrix();
			render.drawBox(box);
		}
	}

	if (_targetScene->optimized())
	{
		_targetCamera->query("scene-items", _constSceneItems);
		ConstSceneTreeItemArray& constSceneItems = _constSceneItems;
		render.setLineSmooth(true);
		render.setLineWidth(1);
		render.setColor(255, 0, 255);
		for (int i = 0; i < constSceneItems.size(); i++)
		{
			SceneTreeConstItem& item = constSceneItems.at(i);
			render.drawSpace(item.space());
		}
	}
}

void MainHandler::slotAttached()
{

}
void MainHandler::slotDetached()
{

}

void MainHandler::mousePressEvent(const BMouseEvent& mouseEvent)
{
	return BRoundHandler::mousePressEvent(mouseEvent);
}
void MainHandler::mouseReleaseEvent(const BMouseEvent& mouseEvent)
{
	return BRoundHandler::mouseReleaseEvent(mouseEvent);
}
void MainHandler::mouseMoveEvent(const BMouseEvent& mouseEvent)
{
	return BRoundHandler::mouseMoveEvent(mouseEvent);
}


